/*
 * OPIAM Suite
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package opiam.admin.applis.demo.utils;

import opiam.admin.applis.demo.beans.Person;

import opiam.admin.faare.service.UserContext;
import opiam.admin.faare.service.services.views.ViewGenerator;

import org.apache.log4j.Logger;

import javax.swing.tree.DefaultMutableTreeNode;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;


/**
 * This class allows to generate the text orgchart.
 */
public class GenOrgChart
{
    /** Instance of logger. */
    private static Logger _logger = Logger.getLogger(GenOrgChart.class);

    /** DOCUMENT ME */
    private static Hashtable upOrgas;

    /** DOCUMENT ME */
    private static int totalnb;

    /**
     * Process the children of the node.
     *
     * @param prefix        Set of spaces.
     * @param node          The current node.
     * @param managersList  Managers list.
     * @param persondn      Dname of the entry.
     * @param isDown        Indicates the current node is lower o the reference node.
     * @param result        The orgchart representation.
     */
    private static void processChildren(String prefix,
                                        DefaultMutableTreeNode node,
                                        ArrayList managersList,
                                        String persondn, boolean isDown,
                                        StringBuffer result, int count
                                       )
    {
        int nbChildren = node.getChildCount();

        /* loop in managers stop condition */
        if (count > totalnb)
        {
            return;
        }

        for (int i = 0; i < nbChildren; i++)
        {
            DefaultMutableTreeNode child =
                (DefaultMutableTreeNode) node.getChildAt(i);
            Hashtable info = (Hashtable) child.getUserObject();
            String dn = (String) info.get("dn");

            if (!managersList.contains(dn) && !persondn.equals(dn))
            {
                _logger.debug("--processChildren cas1 " +
                              child.getUserObject() + " isDown " + isDown
                             );
                processNode(prefix, child, managersList, persondn, isDown,
                            result, count
                           );
            }
            else
            {
                DefaultMutableTreeNode tree =
                    (DefaultMutableTreeNode) upOrgas.get(dn);
                _logger.debug("--processChildren cas2 " + dn + " # " + tree);
                processNode(prefix, tree, managersList, persondn, isDown,
                            result, count
                           );
            }
        }
    }

    /**
     * Process the node.
     *
     * @param prefix  Set of spaces.
     * @param node    The current node.
     * @param managersList  The managers list.
     * @param persondn     The Dname of the entry.
     * @param isDown        Indicates the current node is lower o the reference node.
     * @param result        The orgchart representation.
     */
    private static void processNode(String prefix, DefaultMutableTreeNode node,
                                    ArrayList managersList, String persondn,
                                    boolean isDown, StringBuffer result,
                                    int count
                                   )
    {
        Hashtable info = (Hashtable) node.getUserObject();
        String dn = (String) info.get("dn");
        String title = (String) info.get("title");
        String department = (String) info.get("department");
        String name = (String) info.get("name");
        String href = "<a href=\"navigationLoad.do?dn=" + dn;
        String endhref= "\" target=\"_parent\">";

        if (title == null)
        {
            title = "N/A";
        }

        if (department == null)
        {
            department = "N/A";
        }

        if (dn.equals(persondn))
        {
            isDown = true;
            result.append("<TR><TD class='text_org_chart_current_user'><NOBR>" +
                          prefix + "<B>" + href + "\" class=\"text_org_chart_current_user\"" + 
						  endhref+ name + "</a></B>&nbsp;(" +
                          title + " - " + department + ")</NOBR></TD></TR>"
                         );
        }
        else
        {
            if (isDown == true)
            {
                result.append("<TR><TD class='text_org_chart_down_user'><NOBR>" +
                              prefix + href + "\" class=\"text_org_chart_down_user\"" + 
							  endhref + name + "</a>&nbsp;(" + title +
                              " - " + department + ")" +
                              "</NOBR></TD></TR>"
                             );
            }
            else
            {
                result.append("<TR><TD class='text_org_chart_user'><NOBR>" +
                              prefix + href + "\" class=\"text_org_chart_user\"" + 
							  endhref + name + "</a>&nbsp;(" + title +
                              " - " + department + ")" +
                              "</NOBR></TD></TR>"
                             );
            }
        }

        if (managersList.contains(dn) || isDown)
        {
            processChildren(prefix +
                            "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;",
                            node, managersList, persondn, isDown, result,
                            count + 1
                           );
        }
    }

    /**
     * Get managers of a person, considering only valid DNs
     *
     * @param person person the managers of whose are requested
     *
     * @return list of managers, or empty list
     */
    private static ArrayList getManagers(Person person)
    {
        ArrayList result = new ArrayList();

        Iterator iter = person.getManager().iterator();

        while (iter.hasNext())
        {
            Person curman = (Person) iter.next();

            if (curman != null)
            {
                result.add(curman);
            }
        }

        return result;
    }

    /**
     * Generates the orgChart.
     *
     * @param person  The reference entry
     * @param uplevel   The upper level.
     * @param downlevel   The lower level.
     * @param userContext  The user context.
     *
     * @return the orgChart.
     */
    public static String genOrgChart(Person person, int uplevel, int downlevel,
                                     UserContext userContext
                                    )
    {
        _logger.debug("---begin " + person.getDn());

        Person top = person;
        int nbmanagers = 0;
        ArrayList managersList = new ArrayList(); // liste de tous les managers

        ArrayList headList = new ArrayList(); // liste des tetes d'organigrammes
        ArrayList tempList = new ArrayList(); // liste des tetes courantes
        ArrayList tempList2; // liste des tetes du niveau suivant
        Hashtable headLevels = new Hashtable(); // niveau de chaque tete d'organigramme
        upOrgas = new Hashtable(); // organigramme a un niveau des managers
        tempList.add(person);

        while ((nbmanagers < uplevel) && (tempList.size() > 0))
        {
            tempList2 = new ArrayList();

            Iterator iter = tempList.iterator();

            while (iter.hasNext())
            {
                Person curpers = (Person) iter.next();
                Collection curmanagers = null;

                if (curpers != null)
                {
                    curmanagers = getManagers(curpers);
                }

                if ((curpers != null) && (curmanagers.size() == 0)) // pas de manager, c'est une tete d'organigramme
                {
                    headList.add(curpers);
                    headLevels.put(curpers.getDn(), new Integer(nbmanagers));
                    managersList.add(curpers.getDn());

                    if (!upOrgas.containsKey(curpers.getDn()))
                    {
                        DefaultMutableTreeNode tree =
                            ViewGenerator.getTextOrgChart(userContext,
                                                          "textorgchart",
                                                          curpers, 1
                                                         );
                        upOrgas.put(curpers.getDn(), tree);
                        _logger.debug("orgchart for " + curpers.getDn());
                    }
                }
                else if (curpers != null) // mettre les managers dans la liste du niveau suivant
                {
                    tempList2.addAll(curmanagers);

                    Iterator iter2 = tempList2.iterator();

                    while (iter2.hasNext())
                    {
                        Person cur = (Person) iter2.next();

                        if (cur != null)
                        {
                            managersList.add(cur.getDn());

                            if (!upOrgas.containsKey(cur.getDn()))
                            {
                                DefaultMutableTreeNode tree =
                                    ViewGenerator.getTextOrgChart(userContext,
                                                                  "textorgchart",
                                                                  cur, 1
                                                                 );
                                upOrgas.put(cur.getDn(), tree);
                                _logger.debug("orgchart for " + cur.getDn());
                            }
                        }
                    }
                }
            }

            tempList = tempList2;
            nbmanagers++;
        }

        Iterator iter = tempList.iterator();

        while (iter.hasNext())
        {
            Person curpers = (Person) iter.next();

            if (curpers != null)
            {
                headList.add(curpers);
                headLevels.put(curpers.getDn(), new Integer(nbmanagers));
                managersList.add(curpers.getDn());

                if (!upOrgas.containsKey(curpers.getDn()))
                {
                    DefaultMutableTreeNode tree =
                        ViewGenerator.getTextOrgChart(userContext,
                                                      "textorgchart", curpers, 1
                                                     );
                    upOrgas.put(curpers.getDn(), tree);
                    _logger.debug("orgchart for " + curpers.getDn());
                }
            }
        }

        _logger.debug("---headList " + headList);
        _logger.debug("---headLevels " + headLevels);
        _logger.debug("---managersList " + managersList);

        // orgchart fort current entry
        DefaultMutableTreeNode downtree =
            ViewGenerator.getTextOrgChart(userContext, "textorgchart", person,
                                          downlevel + 1
                                         );
        upOrgas.put(person.getDn(), downtree);
        _logger.debug("down " + downlevel + " for " + person.getDn());

        totalnb = uplevel + downlevel + 1;

        iter = headList.iterator();
        _logger.debug("---before headList loop " + headList.size());

        StringBuffer result = new StringBuffer();

        if (headList.size() > 1)
        {
            result.append("<TR><TD width=\"100%\" class=\"help_text\">");
            result.append("<BR>Several text org charts are displayed because of the presence of multiple managers in one record at least.");
        }

        while (iter.hasNext())
        {
            _logger.debug("# next head");
            result.append("<TR><TD><TABLE cellpadding=\"0\" cellspacing=\"0\" border=\"0\">");
            result.append("<TR><TD><IMG src=\"<%=request.getContextPath()%>/images/spacer.gif\" width=\"25\" height=\"1\" border=\"0\"></TD></TR>");

            Person curmanager = (Person) iter.next();

            DefaultMutableTreeNode firsttree =
                (DefaultMutableTreeNode) upOrgas.get(curmanager.getDn());

            boolean isDown = false;
            int count = 0;

            try
            {
                processNode("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", firsttree,
                            managersList, person.getDn(), isDown, result, count
                           );
            }
            catch (Exception ex)
            {
                _logger.error(ex.getMessage());
                result.append("Invalid manager relationship.");
            }

            result.append("</TABLE></TD></TR>");
        }

        return result.toString();
    }
}
